home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Sound Cards
/
Programming Sound Cards.iso
/
sound_08
/
ctv-mod.asm
< prev
next >
Wrap
Assembly Source File
|
1995-01-01
|
27KB
|
1,385 lines
PAGE ,132
TITLE Sound Blaster Object Module
SUBTTL Main Program
if1
ifdef small
%OUT Small Model
else
%OUT Large Model
endif
endif
ifdef small
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
else
CTV_TEXT SEGMENT WORD PUBLIC 'CODE'
CTV_TEXT ENDS
endif
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ifdef small
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
else
ASSUME CS: CTV_TEXT, DS: DGROUP, SS: DGROUP
endif
PUBLIC _io_addx, _intr_num, _voice_status
PUBLIC _ctv_detect, _ctv_speaker, _ctv_output,
PUBLIC _ctv_halt
PUBLIC _ctv_pause, _ctv_continue, _ctv_uninstall
PUBLIC _ctv_card_here
_DATA SEGMENT WORD PUBLIC 'DATA'
ifdef small
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
else
ASSUME CS: CTV_TEXT, DS: DGROUP, SS: DGROUP
endif
_io_addx DW 220H
_intr_num DB 0
_voice_status DW 0
ORG_INT_ADDX LABEL DWORD
ORG_INT2_ADDX LABEL DWORD
ORG_INT2_OFF DW ?
ORG_INT2_SEG DW ?
ORG_INT3_ADDX LABEL DWORD
ORG_INT3_OFF DW ?
ORG_INT3_SEG DW ?
ORG_INT5_ADDX LABEL DWORD
ORG_INT5_OFF DW ?
ORG_INT5_SEG DW ?
ORG_INT7_ADDX LABEL DWORD
ORG_INT7_OFF DW ?
ORG_INT7_SEG DW ?
;---------------------
; DMA DATA |
;---------------------
DMA_CURRENT_PAGE DB ?
DMA_CURRENT_ADDX DW ?
DMA_CURRENT_COUNT DW ?
PAGE_TO_DMA DB ?
LEN_L_TO_DMA DW ?
LEN_H_TO_DMA DW ?
LAST_DMA_OFFSET DW ?
_DATA ENDS
ifdef small
_TEXT SEGMENT WORD PUBLIC 'CODE'
else
CTV_TEXT SEGMENT WORD PUBLIC 'CODE'
endif
SUBTTL DSP module
WAIT_TIME EQU 0200H
DMA_VOICE_IN EQU 45H
DMA_VOICE_OUT EQU 49H
DSP_ID_CMD EQU 0E0H
DSP_VER_CMD EQU 0E1H
DSP_VI8_CMD EQU 24H
DSP_VO8_CMD EQU 14H
DSP_VO2_CMD EQU 17H
DSP_VO4_CMD EQU 75H
DSP_VO25_CMD EQU 77H
DSP_MDAC1_CMD EQU 61H
DSP_MDAC2_CMD EQU 62H
DSP_MDAC3_CMD EQU 63H
DSP_MDAC4_CMD EQU 64H
DSP_MDAC5_CMD EQU 65H
DSP_MDAC6_CMD EQU 66H
DSP_MDAC7_CMD EQU 67H
DSP_TIME_CMD EQU 40H
DSP_SILENCE_CMD EQU 80H
DSP_PAUSE_DMA_CMD EQU 0D0H
DSP_ONSPK_CMD EQU 0D1H
DSP_OFFSPK_CMD EQU 0D3H
DSP_CONT_DMA_CMD EQU 0D4H
DSP_INTRQ_CMD EQU 0F2H
CMS_TEST_CODE EQU 0C6H
RESET_TEST_CODE EQU 0AAH
CMS_EXIST EQU 1
FM_MUSIC_EXIST EQU 2
CTV_VOICE_EXIST EQU 4
FM_WAIT_TIME EQU 40H
WRITE_DSP_TIME PROC
PUSH CX
MOV CX,WAIT_TIME
MOV AH,AL
WDT10:
IN AL,DX
OR AL,AL
JNS WDT20
LOOP WDT10
STC
JMP SHORT WDT90
WDT20:
MOV AL,AH
OUT DX,AL
CLC
WDT90:
POP CX
RET
WRITE_DSP_TIME ENDP
READ_DSP_TIME PROC
PUSH CX
PUSH DX
MOV DX,_io_addx
ADD DL,0EH
MOV CX,WAIT_TIME
RDT10:
IN AL,DX
OR AL,AL
JS RDT20
LOOP RDT10
STC
JMP SHORT RDT90
RDT20:
SUB DL,4
IN AL,DX
CLC
RDT90:
POP DX
POP CX
RET
READ_DSP_TIME ENDP
WRITE_DSP PROC
MOV AH,AL
MOV AL,0F0H
WD10:
IN AL,DX
OR AL,AL
JS WD10
MOV AL,AH
OUT DX,AL
RET
WRITE_DSP ENDP
READ_DSP PROC
PUSH DX
MOV DX,_io_addx
ADD DL,0EH
SUB AL,AL
RD10:
IN AL,DX
OR AL,AL
JNS RD10
SUB DL,4
IN AL,DX
POP DX
RET
READ_DSP ENDP
RESET_DSP PROC
MOV DX,_io_addx
ADD DL,6
MOV AL,1
OUT DX,AL
IN AL,DX
RDSP05:
INC AL
JNZ RDSP05
OUT DX,AL
MOV CL,20H
RDSP10:
CALL READ_DSP_TIME
CMP AL,0AAH
JE RDSP20
DEC CL
JNZ RDSP10
MOV AX,2
JMP SHORT RDSP90
RDSP20:
SUB AX,AX
RDSP90:
OR AX,AX
RET
RESET_DSP ENDP
VERIFY_IO_CHK PROC
MOV BX,2
MOV AL,DSP_ID_CMD
MOV DX,_io_addx
ADD DX,0CH
CALL WRITE_DSP_TIME
JC VIO90
MOV AL,0AAH
CALL WRITE_DSP_TIME
JC VIO90
CALL READ_DSP_TIME
JC VIO90
CMP AL,055H
JNE VIO90
SUB BX,BX
VIO90:
MOV AX,BX
OR AX,AX
RET
VERIFY_IO_CHK ENDP
VERIFY_INTR PROC
MOV AL,2
MOV DX,OFFSET DUMMY_DMA_INT2
MOV BX,OFFSET DGROUP:ORG_INT2_ADDX
CALL SETUP_INTERRUPT
MOV AL,3
MOV DX,OFFSET DUMMY_DMA_INT3
MOV BX,OFFSET DGROUP:ORG_INT3_ADDX
CALL SETUP_INTERRUPT
MOV AL,5
MOV DX,OFFSET DUMMY_DMA_INT5
MOV BX,OFFSET DGROUP:ORG_INT5_ADDX
CALL SETUP_INTERRUPT
MOV AL,7
MOV DX,OFFSET DUMMY_DMA_INT7
MOV BX,OFFSET DGROUP:ORG_INT7_ADDX
CALL SETUP_INTERRUPT
MOV _intr_num,0
MOV DX,_io_addx
ADD DX,0CH
MOV AL,DSP_INTRQ_CMD
CALL WRITE_DSP
IN AL,21H
PUSH AX
AND AL,01010011B
OUT 21H,AL
SUB AX,AX
MOV CX,WAIT_TIME*4
VI10:
CMP _intr_num,0
JNZ VI90
LOOP VI10
MOV AX,3
VI90:
POP BX
PUSH AX
MOV AL,BL
OUT 21H,AL
MOV AL,2
MOV BX,OFFSET DGROUP:ORG_INT2_ADDX
CALL RESTORE_INTERRUPT
MOV AL,3
MOV BX,OFFSET DGROUP:ORG_INT3_ADDX
CALL RESTORE_INTERRUPT
MOV AL,5
MOV BX,OFFSET DGROUP:ORG_INT5_ADDX
CALL RESTORE_INTERRUPT
MOV AL,7
MOV BX,OFFSET DGROUP:ORG_INT7_ADDX
CALL RESTORE_INTERRUPT
POP AX
OR AX,AX
RET
VERIFY_INTR ENDP
CHK_DSP_VERSION PROC
MOV AL,DSP_VER_CMD
MOV DX,_io_addx
ADD DL,0CH
CALL WRITE_DSP
CALL READ_DSP
MOV AH,AL
CALL READ_DSP
MOV BX,1
CMP AX,101H
JB CDV90
SUB BX,BX
CDV90:
MOV AX,BX
OR AX,AX
RET
CHK_DSP_VERSION ENDP
PAUSE_DSP_DMA PROC
PUSHF
MOV AH,DSP_PAUSE_DMA_CMD
MOV BX,OFFSET DGROUP:_voice_status
SUB CX,CX
MOV DX,_io_addx
ADD DL,0CH
PDD10:
STI ; enable intr. for voice-out intr
CMP CX,[BX] ; to update voice_status
JE PDD90
CLI ; disable intr. for following check
IN AL,DX ; which is timing critical
OR AL,AL
JNS PDD10 ; wait for DSP not ready
PDD20:
IN AL,DX
OR AL,AL
JS PDD20 ; wait for DSP ready
MOV AL,AH
OUT DX,AL ; write pause dma immediately
PDD90:
POPF
RET
PAUSE_DSP_DMA ENDP
SUBTTL DMA module
;--------------------------------------------
; entry: DH = dma mode :
; DL = page :
; AX = current addx :
; CX = current count :
;--------------------------------------------
DMA_ADDX_REG EQU 02H
DMA_COUNT_REG EQU 03H
DMA_MASK_REG EQU 0AH
DMA_MODE_REG EQU 0BH
DMA_FF_REG EQU 0CH
DMA_PAGE_REG EQU 83H
PROG_DMA PROC
PUSH BX
MOV BX,AX
MOV AL,5
OUT DMA_MASK_REG,AL
SUB AL,AL
OUT DMA_FF_REG,AL
MOV AL,DH
OUT DMA_MODE_REG,AL
MOV AL,BL
OUT DMA_ADDX_REG,AL
MOV AL,BH
OUT DMA_ADDX_REG,AL
MOV AL,CL
OUT DMA_COUNT_REG,AL
MOV AL,CH
OUT DMA_COUNT_REG,AL
MOV AL,DL
OUT DMA_PAGE_REG,AL
MOV AL,1
OUT DMA_MASK_REG,AL
POP BX
RET
PROG_DMA ENDP
CALC_20BIT_ADDX PROC
PUSH CX
MOV CL,4
ROL DX,CL
MOV CX,DX
AND DX,0FH
AND CX,0FFF0H
ADD AX,CX
ADC DX,0
POP CX
RET
CALC_20BIT_ADDX ENDP
;-------------------------------------------------
; entry: AL = INTERRUPT NUM |
; DX = new vector ofs, seg is alway CS |
; BX = offset of store buffer :
;-------------------------------------------------
SETUP_INTERRUPT PROC
PUSHF
PUSH BX
PUSH CX
PUSH DX
CLI
MOV CL,AL ; preserve interrupt number for use
ADD AL,8 ; calculate interrupt vector addx
CBW
SHL AL,1
SHL AL,1
MOV DI,AX
PUSH ES ; setup and preserve interrupt
SUB AX,AX
MOV ES,AX
MOV AX,ES:[DI]
MOV [BX],AX
MOV ES:[DI],DX
MOV AX,ES:[DI+2]
MOV [BX+2],AX
MOV ES:[DI+2],CS
POP ES
POP DX
POP CX
POP BX
POPF
RET
SETUP_INTERRUPT ENDP
;-------------------------------------------------
; entry: AL = INTERRUPT NUM |
; BX = offset to stored addx |
;-------------------------------------------------
RESTORE_INTERRUPT PROC
PUSHF
CLI
MOV CL,AL
ADD AL,8 ; calculate interrupt vector addx
CBW
SHL AL,1
SHL AL,1
MOV DI,AX
PUSH ES ; restore interrupt vector
SUB AX,AX
MOV ES,AX
MOV AX,[BX]
MOV ES:[DI],AX
MOV AX,[BX+2]
MOV ES:[DI+2],AX
POP ES
MOV AH,1
SHL AH,CL
IN AL,21H
OR AL,AH
OUT 21H,AL
POPF
RET
RESTORE_INTERRUPT ENDP
DUMMY_DMA_INT2 PROC FAR
PUSH DX
MOV DL,2
JMP SHORT DUMMY_DMA_ISR
DUMMY_DMA_INT2 ENDP
DUMMY_DMA_INT3 PROC FAR
PUSH DX
MOV DL,3
JMP SHORT DUMMY_DMA_ISR
DUMMY_DMA_INT3 ENDP
DUMMY_DMA_INT5 PROC FAR
PUSH DX
MOV DL,5
JMP SHORT DUMMY_DMA_ISR
DUMMY_DMA_INT5 ENDP
DUMMY_DMA_INT7 PROC FAR
PUSH DX
MOV DL,7
DUMMY_DMA_ISR:
PUSH DS
PUSH AX
MOV AX,DGROUP
MOV DS,AX
MOV _intr_num,DL
MOV DX,_io_addx
ADD DX,0EH
IN AL,DX
MOV AL,20H
OUT 20H,AL
POP AX
POP DS
POP DX
IRET
DUMMY_DMA_INT7 ENDP
DMA_OUT_INTR PROC
PUSH DS
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH BP
CLD
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
MOV DX,_io_addx
ADD DL,0EH
IN AL,DX
MOV AX,LEN_L_TO_DMA
OR AX,AX
JNZ VO_INT10
CALL END_DMA_TRANSFER
JMP SHORT VO_INT90
VO_INT10:
CALL DMA_OUT_TRANSFER
VO_INT90:
MOV AL,20H
OUT 20H,AL
POP BP
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
IRET
DMA_OUT_INTR ENDP
DMA_OUT_TRANSFER PROC
MOV CX,0FFFFH ; get current page end address
CMP PAGE_TO_DMA,0 ; last page to dma ?
JNZ DOT10 ; no, skip
INC PAGE_TO_DMA
MOV CX,LAST_DMA_OFFSET ; get end addx
DOT10:
SUB CX,DMA_CURRENT_ADDX ; calcutate current page addx
MOV DMA_CURRENT_COUNT,CX
INC CX
JZ DOT20
SUB LEN_L_TO_DMA,CX
SBB LEN_H_TO_DMA,0
JMP SHORT DOT30
DOT20:
DEC LEN_H_TO_DMA
DOT30:
MOV DH,DMA_VOICE_OUT
MOV DL,DMA_CURRENT_PAGE
MOV AX,DMA_CURRENT_ADDX
MOV CX,DMA_CURRENT_COUNT
CALL PROG_DMA
DEC PAGE_TO_DMA
INC DMA_CURRENT_PAGE
MOV DMA_CURRENT_ADDX,0
MOV CX,DMA_CURRENT_COUNT
MOV DX,_io_addx
ADD DL,0CH
MOV AL,DSP_VO8_CMD
CALL WRITE_DSP
MOV AL,CL
CALL WRITE_DSP
MOV AL,CH
CALL WRITE_DSP
DOT90:
RET
DMA_OUT_TRANSFER ENDP
END_DMA_TRANSFER PROC
MOV AL,5
OUT DMA_MASK_REG,AL
MOV CL,_intr_num
MOV AH,1
SHL AH,CL
IN AL,21H
OR AL,AH
OUT 21H,AL
MOV AL,_intr_num
MOV BX,OFFSET DGROUP:ORG_INT_ADDX
CALL RESTORE_INTERRUPT
MOV _voice_status,0
MOV DX,_io_addx
ADD DL,0EH
IN AL,DX
RET
END_DMA_TRANSFER ENDP
;---------------------------------------
; WAIT_FM_STATUS :
; entry: AL = status to wait :
; 3 msb is concern :
; exit : AX destroy :
; carry set for fail :
; carry clr for pass :
;---------------------------------------
WAIT_FM_STATUS PROC
PUSH CX
PUSH DX
MOV CX,FM_WAIT_TIME
MOV AH,AL
AND AH,0E0H ; only 3 msb are FM status
MOV DX,_io_addx
ADD DL,8
WFS10:
IN AL,DX
AND AL,0E0H
CMP AH,AL
JE WFS20
LOOP WFS10
STC
JMP SHORT WFS90
WFS20:
CLC
WFS90:
POP DX
POP CX
RET
WAIT_FM_STATUS ENDP
;---------------------------------------
; WRITE_FM :
; entry: AH = data value :
; AL = addx value :
; exit : AX destroy :
; DX destroy :
;---------------------------------------
WRITE_FM PROC
MOV DX,_io_addx
ADD DL,8
OUT DX,AL
CALL FM_DELAY
MOV AL,AH
INC DX
OUT DX,AL
CALL FM_DELAY
RET
WRITE_FM ENDP
FM_DELAY PROC
PUSH AX
PUSH DX
MOV DX,_io_addx
ADD DL,8
IN AL,DX
IN AL,DX
IN AL,DX
IN AL,DX
IN AL,DX
POP DX
POP AX
RET
FM_DELAY ENDP
ifdef small
_ctv_detect PROC
else
_ctv_detect PROC FAR
endif
PUSH DS
PUSH ES
PUSH DI
PUSH SI
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
CALL RESET_DSP
JNZ ID90
CALL VERIFY_IO_CHK
JNZ ID90
CALL CHK_DSP_VERSION
JNZ ID90
CALL VERIFY_INTR
JNZ ID90
MOV AL,1 ; on speaker
CALL ON_OFF_SPEAKER
SUB AX,AX
ID90:
POP SI
POP DI
POP ES
POP DS
RET
_ctv_detect ENDP
SPK_STK STRUC
ifdef small
DW ?
else
DD ?
endif
DW ?
SPK_FLAG DW ?
SPK_STK ENDS
ifdef small
_ctv_speaker PROC
else
_ctv_speaker PROC FAR
endif
PUSH BP
MOV BP,SP
PUSH DS
MOV AX,DGROUP
MOV DS,AX
MOV AX,[BP+SPK_FLAG]
CALL ON_OFF_SPEAKER
POP DS
POP BP
RET
_ctv_speaker ENDP
ON_OFF_SPEAKER PROC
MOV DX,_io_addx
ADD DX,0CH
MOV AH,DSP_ONSPK_CMD
OR AL,AL
JNZ OOS10
MOV AH,DSP_OFFSPK_CMD
OOS10:
MOV AL,AH
CALL WRITE_DSP
SUB AX,AX ; inidcate no error
RET
ON_OFF_SPEAKER ENDP
OUT_STK STRUC
ifdef small
DW ? ; one word ret addx
else
DD ? ; double word ret addx
endif
DW ?
BUF_OFF DW ?
BUF_SEG DW ?
COUNT DW ?
SAMPLING DW ?
OUT_STK ENDS
ifdef small
_ctv_output PROC
else
_ctv_output PROC FAR
endif
PUSH BP
MOV BP,SP
PUSH DS
PUSH ES
PUSH DI
PUSH SI
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
CMP _voice_status,0
JZ OV10
MOV AX,1
JMP OV90
OV10:
MOV _voice_status,1
MOV DX,_io_addx
ADD DL,0CH
MOV DX,0FH ; calculate sampling rate value for
MOV AX,4240H ; DSP
MOV CX,[BP+SAMPLING]
DIV CX
MOV CL,AL
NEG CL
MOV DX,_io_addx
ADD DL,0CH
MOV AL,DSP_TIME_CMD
CALL WRITE_DSP
MOV AL,CL
CALL WRITE_DSP
MOV AL,_intr_num
MOV DX,OFFSET DMA_OUT_INTR
MOV BX,OFFSET DGROUP:ORG_INT_ADDX
CALL SETUP_INTERRUPT
MOV CL,_intr_num
MOV AH,1
SHL AH,CL
NOT AH
IN AL,21H
AND AL,AH
OUT 21H,AL
MOV DX,[BP+BUF_SEG]
MOV AX,[BP+BUF_OFF]
CALL CALC_20BIT_ADDX
MOV DMA_CURRENT_PAGE,DL
MOV DMA_CURRENT_ADDX,AX
MOV CX,[BP+COUNT]
MOV LEN_L_TO_DMA,CX
MOV LEN_H_TO_DMA,0
ADD AX,[BP+COUNT]
ADC DL,0
SUB AX,1
SBB DL,0
MOV LAST_DMA_OFFSET,AX
SUB DL,DMA_CURRENT_PAGE
MOV PAGE_TO_DMA,DL
CALL DMA_OUT_TRANSFER
SUB AX,AX
OV90:
POP SI
POP DI
POP ES
POP DS
POP BP
RET
_ctv_output ENDP
ifdef small
_ctv_halt PROC
else
_ctv_halt PROC FAR
endif
PUSH DS
PUSH ES
PUSH DI
PUSH SI
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
MOV AX,1
CMP _voice_status,0
JZ TVP90
CALL PAUSE_DSP_DMA
CALL END_DMA_TRANSFER
SUB AX,AX
TVP90:
POP SI
POP DI
POP ES
POP DS
RET
_ctv_halt ENDP
ifdef small
_ctv_pause PROC
else
_ctv_pause PROC FAR
endif
PUSH DS
PUSH ES
PUSH DI
PUSH SI
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
MOV AX,1
CMP _voice_status,1
JNE PV90
CALL PAUSE_DSP_DMA
SUB AX,AX
PV90:
POP SI
POP DI
POP ES
POP DS
RET
_ctv_pause ENDP
ifdef small
_ctv_continue PROC
else
_ctv_continue PROC FAR
endif
PUSH DS
PUSH ES
PUSH DI
PUSH SI
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
MOV AX,1
CMP _voice_status,1
JNE CV90
MOV DX,_io_addx
ADD DL,0CH
MOV AL,DSP_CONT_DMA_CMD
CALL WRITE_DSP
SUB AX,AX
CV90:
POP SI
POP DI
POP ES
POP DS
RET
_ctv_continue ENDP
ifdef small
_ctv_uninstall PROC
else
_ctv_uninstall PROC FAR
endif
PUSH DS
PUSH ES
PUSH DI
PUSH SI
MOV AX,DGROUP
MOV DS,AX
MOV ES,AX
CMP _voice_status,0
JZ UI90
CALL PAUSE_DSP_DMA
CALL END_DMA_TRANSFER
UI90:
SUB AL,AL
CALL ON_OFF_SPEAKER
SUB AX,AX
POP SI
POP DI
POP ES
POP DS
RET
_ctv_uninstall ENDP
;-----------------------------------------------------------
; usage: :
; unint ctv_card_here() :
; description: :
; detect the Game Blaster or Sound Blaster Card and :
; the configuration :
; entry: :
; the global i/o addx, ct_io_addx must set to a default :
; value, 2x0H, before call. :
; exit: :
; High Byte = 0 :
; Low Byte format - :
; 0000 0001 : C/MS music exists :
; 0000 0010 : FM music exists :
; 0000 0100 : CTV Voice exists :
;-----------------------------------------------------------
ifdef small
_ctv_card_here PROC near
else
_ctv_card_here PROC far
endif
PUSH DS ; for multi data model, set DS to
MOV AX,DGROUP ; DGROUP segment
MOV DS,AX
SUB BX,BX ; assume Creative Card doesn't exist,
; return 0
;-----------------------------
; detect Game Blaster :
;-----------------------------
MOV DX,_io_addx ; get default i/o addx
ADD DL,6 ; write the test code to
MOV AL,CMS_TEST_CODE ; output port 2x6H
OUT DX,AL ; ...
SUB AL,AL
ADD DL,4 ; read the data back from
OUT DX,AL
IN AL,DX ; input port 2xAH
CMP AL,CMS_TEST_CODE ; the same data ?
JNE CARD10 ; no, try Sound Blaster Card
SUB DL,4 ; to ensure, try inverse data
MOV AL,NOT CMS_TEST_CODE ; output port 2x6H
OUT DX,AL ; ...
SUB AL,AL
ADD DL,4 ; read the data back from
OUT DX,AL
IN AL,DX ; input port 2xAH
CMP AL,NOT CMS_TEST_CODE ; the same data ?
JNE CARD10 ; no, try Sound Blaster Card
MOV BX,CMS_EXIST
JMP SHORT CARD50
;--------------------------------------
; detect the Sound Blaster Card :
;--------------------------------------
CARD10:
CALL RESET_DSP
JNZ CARD50
CARD40:
MOV DX,_io_addx
ADD DL,0CH
MOV AL,DSP_ID_CMD
CALL WRITE_DSP_TIME
JC CARD50
MOV AL,CMS_TEST_CODE
CALL WRITE_DSP_TIME
JC CARD50
CALL READ_DSP_TIME
JC CARD50
CMP AL,NOT CMS_TEST_CODE
JNE CARD50
MOV BX,CMS_EXIST + CTV_VOICE_EXIST
;-----------------------------
; detect the FM Music :
;-----------------------------
CARD50:
MOV AX,0001H ; reset the FM chip
CALL WRITE_FM
MOV AX,6004H ; mask of timer 1 & 2
CALL WRITE_FM
MOV AX,8004H ; reset irq and both timer flags
CALL WRITE_FM
MOV AL,0 ; read for 3 msb clear
CALL WAIT_FM_STATUS
JC CARD90
MOV AX,0FF02H ; write timer 1 count
CALL WRITE_FM
MOV AX,2104H ; start timer 1
CALL WRITE_FM
MOV AL,0C0H ; wait for irq and timer 1 end
CALL WAIT_FM_STATUS
JC CARD90
MOV AX,6004H ; mask of timer 1 & 2
CALL WRITE_FM
MOV AX,8004H ; reset irq and both timer flags
CALL WRITE_FM
ADD BX,FM_MUSIC_EXIST
CARD90:
MOV AX,BX
POP DS
RET
_ctv_card_here ENDP
ifdef small
_TEXT ENDS
else
CTV_TEXT ENDS
endif
END